﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Reflection;

public class PlayerPrefsManager
{
    private static PlayerPrefsManager instance;
    public static PlayerPrefsManager Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new PlayerPrefsManager();
            }
            return instance;
        }
    }

    private PlayerPrefsManager()
    { }


    //储存数据，通过传入的Object类型来获取它的原始类型
    public void SaveData(object data, string keyName)
    {
        

        //获取原始类型
        Type type = data.GetType();

        //获取全部字段
        FieldInfo[] fieldInfos = type.GetFields();
        FieldInfo info;
        for (int i = 0; i < fieldInfos.Length; i++)
        {
            info = fieldInfos[i];
            //info.FieldType.Name 获取字段类型
            //info.Name           获取字段名
            string name = keyName + "_" + type.Name + "_" + info.FieldType.Name + "_" + info.Name;
            //拿取该字段的值
            SaveValue(info.GetValue(data), name);
        }

        PlayerPrefs.Save();
    }

    private void SaveValue(object data, string keyName)
    {
        Type fieldType = data.GetType();

        if (fieldType == typeof(int))
        {
            PlayerPrefs.SetInt(keyName, (int)data);
        }
        else if (fieldType == typeof(float))
        {
            PlayerPrefs.SetFloat(keyName, (float)data);
        }
        else if (fieldType == typeof(string))
        {
            PlayerPrefs.SetString(keyName, (string)data);
        }
        else if (fieldType == typeof(bool))
        {
            PlayerPrefs.SetInt(keyName, (bool)data ? 1 : 0);
        }
        //对于List类型，需要使用IsAssignableFrom来判断当前的data的fieldType是否为IList的子类
        else if (typeof(IList).IsAssignableFrom(fieldType))
        {
            //里氏替换
            IList list = data as IList;
            //记录List的长度

            PlayerPrefs.SetInt(keyName, list.Count);

            //对于存储的类型,遍历它,并利用递归去辨别
            for (int i = 0; i < list.Count; i++)
            {
                //保证键的唯一性
                SaveValue(list[i], keyName + "_" + i);
            }
        }
        else if (typeof(IDictionary).IsAssignableFrom(fieldType))
        {
            //里氏替换
            IDictionary dic = data as IDictionary;
            PlayerPrefs.SetInt(keyName, dic.Count);
            int index = 0;
            foreach (object key in dic.Keys)
            {
                SaveValue(key, keyName + "_key_" + index);
                SaveValue(dic[key], keyName + "_value_" + index);
                index++;//维护唯一性
            }
        }
        else //自定义类型
        {
            SaveData(data, keyName);
        }

    }

    public object LoadData(Type type, string keyName)
    {
        //先把对象给反射实例出来，这个对象必须拥有默认实例构造函数
        object data = Activator.CreateInstance(type);

        //拿到全部数据段
        FieldInfo[] infos = type.GetFields();
        FieldInfo info;
  
        for (int i = 0; i < infos.Length; i++)
        {
            info = infos[i];    
            string loadName = keyName + "_" + type.Name + "_" + info.FieldType.Name + "_" + info.Name;

            info.SetValue(data, LoadValue(info.FieldType, loadName));
        }


        return data;
    }

    private object LoadValue(Type fieldType, string loadName)
    {
        if (fieldType == typeof(int))
        {
            return PlayerPrefs.GetInt(loadName,0);
        }
        else if (fieldType == typeof(float))
        {
            return PlayerPrefs.GetFloat(loadName, 0);
        }
        else if (fieldType == typeof(string))
        {
            return PlayerPrefs.GetString(loadName, "");
        }
        else if (fieldType == typeof(bool))
        {
            return PlayerPrefs.GetInt(loadName, 0)==1?true:false;
        }
        else if (typeof(IList).IsAssignableFrom(fieldType))
        {
            int cnt = PlayerPrefs.GetInt(loadName, 0);
            Type[] genericType = fieldType.GetGenericArguments();

            //实例化一个List对象
            IList list = Activator.CreateInstance(fieldType) as IList;

            for (int i = 0; i < cnt; i++)
            {
                list.Add(LoadValue(genericType[0], loadName + "_" + i));
            }

            return list;
        }
        else if (typeof(IDictionary).IsAssignableFrom(fieldType))
        {
            int cnt = PlayerPrefs.GetInt(loadName);
            IDictionary dic = Activator.CreateInstance(fieldType) as IDictionary;

            Type[] genericType = fieldType.GetGenericArguments();
            for (int i = 0; i < cnt; i++)
            {
                dic.Add(LoadValue(genericType[0], loadName + "_key_" + i),
                    LoadValue(genericType[1], loadName + "_value_" + i));
            }
            return dic;
        }
        else
        {
            return LoadData(fieldType, loadName);
        }

        return null;
    }
    
}
